package ufcg.metci.huffman;

import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Stack;

import ufcg.metci.util.FileControl;

/**
 * Projeto para disciplina de Metodologia Científica - UFCG - 2012.1
 * 
 * @author Ana Clara Lacerda
 * @author Rodolfo Marinho
 *
 * Classe que implementa o algorirmo de
 * Huffman para compressão dos dados
 */
public class HuffmanCompress extends Huffman{

	private String originalContent;

	public static void main(String[] args) {
		String inputFileName = "teste.txt";
		String outputFileName = "teste";
		
		String compressedContent = new HuffmanCompress().compressFile(inputFileName);
		FileControl.saveCompressedFile(compressedContent, inputFileName, outputFileName);
	}
	
	/**
	 * Compress the bytes from the given file
	 * 
	 * @param fileInput
	 * @return New sequence of bytes
	 */
	public String compressFile(String fileInput) {

		FileInputStream file = null;

		try {
			originalContent = FileControl.read(fileInput); // guarda o conteúdo originaldoarquivo

			byte[] bytesRead = originalContent.getBytes();

			HuffmanNode rootNode = buildTree(buildFrequency(bytesRead)); // constrói a árvore de Huffman
			buildCodes(rootNode, new Stack<Byte>()); // gera os códigos para cada simbolo

			return buildContent(); // retorno a nova e comprimida sequencia de bytes

		} catch (FileNotFoundException e) {
			// TODO stderr
		} catch (IOException e) {
			// TODO stderr
		}
		return fileInput;
	}

	private int[] buildFrequency(byte[] bytesRead) {
		int[] frequency = new int[256];
		for (char c : new String(bytesRead).toCharArray()) {
			frequency[c]++;
		}
		return frequency;
	}

	private HuffmanLeaf findNode(String value) {
		for (int i = 0; i < numberOfSymbols; i++) {
			HuffmanLeaf aux = (HuffmanLeaf) nodes.get(i);
			if (aux.getValue().equals(value)) {
				return aux;
			}
		}
		return null;
	}

	/**
	 * Create new content based on the codes generated
	 * 
	 * @return new and compressed sequence of bytes
	 */
	public String buildContent() {
		String coded = originalContent;
		String dict = "-D-AFW";
		HuffmanLeaf leaf;
		for (int i = 0; i < numberOfSymbols; i++) {
			leaf = findNode((String) foundSymbols.get(i));
			dict = dict + leaf.getValue() + leaf.getFrequency() + "||";
			coded = coded.replace(leaf.getValue(), leaf.getCode());
		}
		return coded + dict;
	}

}
